#include "rocks.h"
#include "bangdots.h"
#include "datafun.h"
#include "gas-plume.h"
#include "greeblies.h"
#include "random_gen.h"
#include "rockdodger_globals.h"
#include "sound.h"
#include <assert.h>
#include <math.h>

struct rock_struct rock[MAX_ROCKS], *rockptr = rock;

sdl_surfaces_t *surf_rocks = NULL; //!< All the rocky asteroid surfaces.
sdl_surfaces_t *surf_dead_rocks = NULL; //!< All the dead asteroid surfaces.
sdl_surfaces_t *surf_lithiumrocks = NULL; //!< All the heavy-duty asteroid surfaces.
sdl_surfaces_t *surf_dead_lithiumrocks = NULL; //!< All the dead/hot heavy-duty asteroid surfaces.
sdl_surfaces_t *surf_icerocks = NULL; //!< All the ice asteroid surfaces.
sdl_surfaces_t *surf_dead_icerocks = NULL; //!< All the dead/hot ice asteroid surfaces.


SDL_Surface *get_rock_surface(int rockidx, int hot) {
  sdl_surfaces_t *surfs;
  unsigned short imgidx = rock[rockidx].type_number;

  assert(rock[rockidx].type_class <= 2);
  switch(rock[rockidx].type_class) {
  case 2:
    surfs = hot == 1 ? surf_dead_icerocks : surf_icerocks;
    break;
  case 1:
    surfs = hot == 1 ? surf_dead_lithiumrocks : surf_lithiumrocks;
    break;
  default:
    //Defaults to normal rocks so that the game does (somehow) function.
    surfs = hot == 1 ? surf_dead_rocks : surf_rocks;
    break;
  }
  assert(imgidx < surfs->num_surfaces);
  return surfs->surfaces[imgidx];
}


void heat_rock_up(int rockidx, float mvmt) {
  assert(rockidx >= 0);
  assert(rockidx < MAX_ROCKS);
  struct rock_struct *rptr = rock + rockidx;
  rock[rockidx].heat += mvmt / rock[rockidx].heat_capacity;
  if(rock[rockidx].type_class == 2) {
    SDL_Surface *image = get_rock_surface(rockidx, 0);
    float size = (image->w + image->h) / 2.0;
    create_plumedots(9, rptr->x + image->w / 2, rptr->y + image->h / 2, rptr->plume_angle, 2, 17.27);
    rptr->xvel += 1.442 * cosf(rptr->plume_angle) / size;
    rptr->yvel += 1.442 * sinf(rptr->plume_angle) / size;
  }
}


void create_rock(float rockspeed) {
  rockptr++;
  if(rockptr - rock >= MAX_ROCKS)
    rockptr = rock;

  if(!rockptr->active && !rockptr->greeb) {
    rockptr->x = (float) xsize;
    rockptr->y = rnd() * ysize;
    rockptr->xvel = -(rockspeed) * (1 + rnd());
    rockptr->yvel = (rockspeed / 3.0) * (rnd() - 0.5);

    if(level > 3 && rnd() < 0.0713645) { //Start with third level...
      rockptr->type_class = 2;
      rockptr->type_number = random() % surf_icerocks->num_surfaces;
      rockptr->heat_capacity = 1.0 / 3;
      rockptr->plume_angle = 360 * rnd();
    } else if(level > 5 && rnd() < 0.068073) { //Start with fifth level...
      rockptr->type_class = 1;
      rockptr->type_number = random() % surf_lithiumrocks->num_surfaces;
      rockptr->heat_capacity = 34.0 / 49.0;
    } else {
      rockptr->type_class = 0;
      rockptr->type_number = random() % NROCKS;
      rockptr->heat_capacity = 1.0 / 3;
    }
    rockptr->heat = 0;
    rockptr->active = 1;
  }
}


void display_rocks(SDL_Surface *surf_screen) {
  int i;
  static int last_rock = 1;
  SDL_Rect dest;

  dest.w = 0;
  dest.h = 0;
  for(i = 0; i < MAX_ROCKS; i++) {
    struct rock_struct *r = &rock[i];
    if(r->active) {
      SDL_Surface *image = get_rock_surface(i, 0);
      if(!r->greeb)
	last_rock = i;
      dest.x = (int) r->x;
      dest.y = (int) r->y;

      // Draw the rock
      SDL_BlitSurface(image, NULL, surf_screen, &dest);

      // Draw the heated part of the rock, in an alpha which reflects the
      // amount of heat in the rock.
      if(r->heat > 0) {
	SDL_Surface *deadrock = get_rock_surface(i, 1);
	SDL_SetAlpha(deadrock, SDL_SRCALPHA, r->heat * 255 / image->h);
	dest.x = (int) r->x;	// kludge
	SDL_BlitSurface(deadrock, NULL, surf_screen, &dest);
	if(rnd() < 0.3)
	  r->heat -= movementrate;
      }
      // If the rock is heated past a certain point, the water content of
      // the rock flashes to steam, releasing enough energy to destroy
      // the rock in spectacular fashion.
      if(rock[i].heat > image->h) {
	int g;

	rock[i].active = 0;
	play_sound(1 + (int) (rnd() * 3));
	makebangdots(rock[i].x, rock[i].y, rock[i].xvel, rock[i].yvel,
		     image, 10, 3);

	// If a greeblie was going to this rock
	if((g = rock[i].greeb)) {
	  // ...and had landed, then the greeblie explodes too.
	  if(greeb[g].landed)
	    kill_greeb(g);
	  else {
	    // If the greeblie is not yet landed, then it must now
	    // find another rock to jump to. Choose the last active
	    // rock found.
	    rock[i].greeb = 0;
	    rock[last_rock].greeb = g;
	    greeb[g].target_rock_number = last_rock;
	  }
	}
      }
    }
    // Draw any greeblies attached to (or going to) the rock, whether the rock is active or not.
    if(r->greeb && greeb[r->greeb].target_rock_number == i)
      display_greeb(&greeb[r->greeb], surf_screen);
  }
}


void update_rocks(void) {
  int i;
  for(i = 0; i < MAX_ROCKS; i++)
    if(rock[i].active) {
      rock[i].x += rock[i].xvel * movementrate;
      rock[i].y += rock[i].yvel * movementrate;
      if(rock[i].x < -32.0)
	rock[i].active = 0;
    }
}


void *init_rocks(void) {
  assert(surf_rocks == NULL && surf_dead_rocks == NULL);
  surf_rocks = load_images_ck("rock%hd.bmp", 0, 255, 0);
  surf_dead_rocks = load_images_ck("deadrock%hd.bmp", 0, 255, 0);
  surf_lithiumrocks = load_images_ck("lithiumrock.%02hX.ilbm", 0, 255, 0);
  surf_dead_lithiumrocks = load_images_ck("deadlithiumrock.%02hX.ilbm", 0, 255, 0);
  surf_icerocks = load_images_ck("icerock.%02hX.png", 0, 255, 0);
  surf_dead_icerocks = load_images_ck("deadicerock.%02hX.png", 0, 255, 0);
  if(!surf_rocks || !surf_dead_rocks ||
     !surf_lithiumrocks || !surf_dead_lithiumrocks ||
     !surf_icerocks || !surf_dead_icerocks
     ) return NULL;
  assert(surf_rocks->num_surfaces == surf_dead_rocks->num_surfaces);
  assert(surf_rocks->num_surfaces >= NROCKS);
  assert(surf_dead_lithiumrocks->num_surfaces == surf_lithiumrocks->num_surfaces);
  assert(surf_dead_icerocks->num_surfaces == surf_icerocks->num_surfaces);
  return surf_rocks;
}
